package com.samphanie.auiu.biz_login

import android.app.Application
import android.content.Context
import android.content.Intent
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import com.samphanie.auiu.biz_login.api.AccountApi
import com.samphanie.auiu.pub_mod.model.TokenInfo
import com.samphanie.auiu.pub_mod.model.UserProfile
import com.samphanie.auiu.common.http.ApiFactory
import com.samphanie.auiu.common.utils.LocalCache
import com.samphanie.auiu.library.cache.AuiuStorage
import com.samphanie.auiu.library.executor.AuiuExecutor
import com.samphanie.auiu.library.restful.AuiuCallback
import com.samphanie.auiu.library.restful.AuiuResponse
import com.samphanie.auiu.library.utils.AppGlobals

/**
 * @author ZSY
 */
object AccountManager {

    private const val JWT_TOKEN = "JWT_TOKEN"
    private const val JWT_TOKEN_PREFIX = "JWT_TOKEN_PREFIX"
    private const val USER_PROFILE_KEY = "user_profile"

    private var userProfile: UserProfile? = null

    private var tokenHeader: String? = null
    private var token: String? = null

    @Volatile
    private var isFetching = false

    private val loginLiveData = MutableLiveData<Boolean>()
    private val loginForeverObservers = mutableListOf<Observer<Boolean>>()

    private val profileLiveData = MutableLiveData<UserProfile>()
    private val profileForeverObservers = mutableListOf<Observer<UserProfile?>>()

    fun login(context: Context? = AppGlobals.get(), observer: Observer<Boolean>) {
        if (context is LifecycleOwner) {
            loginLiveData.observe(context, observer)
        } else {
            loginLiveData.observeForever(observer)
            loginForeverObservers.add(observer)
        }

        val intent = Intent(context, LoginActivity::class.java)
        if (context is Application) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        if (context == null) {
            throw IllegalStateException("context must not be null.")
        }

        context.startActivity(intent)
    }

    fun loginSuccess(data: TokenInfo) {
        LocalCache.getInstance().put(JWT_TOKEN, data.token)
        LocalCache.getInstance().put(JWT_TOKEN_PREFIX, data.tokenHead)
        tokenHeader = data.tokenHead
        token = data.token
        loginLiveData.value = true
        clearLoginForeverObservers()
    }

    private fun clearLoginForeverObservers() {
        for (observer in loginForeverObservers) {
            loginLiveData.removeObserver(observer)
        }
        loginForeverObservers.clear()
    }

    fun isLogin(): Boolean {
        return getAuthorization().isNotBlank()
    }

    fun getAuthorization(): String {
        if (token.isNullOrBlank() || tokenHeader.isNullOrBlank()) {
            token = LocalCache.getInstance().getString(JWT_TOKEN)
            tokenHeader = LocalCache.getInstance().getString(JWT_TOKEN_PREFIX)
        }
        return "$tokenHeader$token"
    }

    @Synchronized
    fun getUserProfile(lifecycleOwner: LifecycleOwner?, observer: Observer<UserProfile?>, onlyCache: Boolean) {
        if (lifecycleOwner == null) {
            profileLiveData.observeForever(observer)
            profileForeverObservers.add(observer)
        } else {
            profileLiveData.observe(lifecycleOwner, observer)
        }

        if (userProfile != null && onlyCache) {
            profileLiveData.postValue(userProfile)
            return
        }

        if (isFetching) return
        isFetching = true
        ApiFactory.create(AccountApi::class.java).profile()
            .enqueue(object : AuiuCallback<UserProfile> {
                override fun onSuccess(response: AuiuResponse<UserProfile>) {
                    if (response.successful() && response.data != null) {
                        userProfile = response.data

                        AuiuExecutor.executor(runnable = {
                            AuiuStorage.saveCache(USER_PROFILE_KEY, userProfile)
                            isFetching = false
                        })

                        profileLiveData.value = userProfile
                    } else {
                        profileLiveData.value = null
                    }
                    clearProfileForeverObservers()
                }

                override fun onFailed(throwable: Throwable) {
                    isFetching = false
                    profileLiveData.postValue(null)
                    clearProfileForeverObservers()
                }
            })
    }

    private fun clearProfileForeverObservers() {
        for (observer in profileForeverObservers) {
            profileLiveData.removeObserver(observer)
        }
        profileForeverObservers.clear()
    }

}